/*
 [The "BSD license"]
 Copyright (c) 2011-2011 Joel Li (李家智)
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 1. Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
 2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
 3. The name of the author may not be used to endorse or promote products
     derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.bee.tl.core;

import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.antlr.runtime.Token;

/**
 * 
 * @author joelli
 * @create 2011-6-14
 */
public class ExpRuntime
{

	BeeCommonNodeTree lastNode = null;
	boolean continueFormat = true;

	public ExpRuntime()
	{

	}

	public boolean condition(BeeCommonNodeTree exp, Context ctx)
	{

		try
		{
			int tokeType = exp.getToken().getType();
			switch (tokeType)
			{
				case BeeParser.VAR_REFER:
				{
					Object o = evalVarRef(exp.getChildren(), ctx, exp);
					if (o instanceof Boolean)
					{
						return ((Boolean) o).booleanValue();
					}
					else
					{
						BeeCommonNodeTree errorNode = this.lastNode;
						throw new BeeRuntimeException(BeeRuntimeException.BOOLEAN_EXPECTED_ERROR, lastNode.getToken());
					}
				}
				case BeeParser.EQUAL:
				{
					return condtionEqualCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);

				}
				case BeeParser.LARGE:
				{
					int result = condtionCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);
					return result > 0;
				}
				case BeeParser.LARGE_EQUAL:
				{
					int result = condtionCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);
					return result > 0 || result == 0;
				}
				case BeeParser.LESS:
				{
					int result = condtionCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);
					return result < 0;
				}
				case BeeParser.LESS_EQUAL:
				{
					int result = condtionCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);
					return result < 0 || result == 0;
				}
				case BeeParser.NOT_EQUAL:
				{
					return !condtionEqualCompare((BeeCommonNodeTree) exp.getChild(0),
							(BeeCommonNodeTree) exp.getChild(1), ctx);

				}
				case BeeParser.NOT:
				{
					return !condition((BeeCommonNodeTree) exp.getChild(0), ctx);
				}
				case BeeParser.OR:
				{

					return condition((BeeCommonNodeTree) exp.getChild(0), ctx)
							|| condition((BeeCommonNodeTree) exp.getChild(1), ctx);
				}
				case BeeParser.AND:
				{

					return condition((BeeCommonNodeTree) exp.getChild(0), ctx)
							&& condition((BeeCommonNodeTree) exp.getChild(1), ctx);
				}

				default:
				{

					throw new BeeRuntimeException(BeeRuntimeException.DO_NOT_SUPPORT, exp.getToken());
				}
			}
		}
		catch (BeeRuntimeException ex)
		{
			throw ex;
		}
		catch (Exception ex)
		{

			throw new BeeRuntimeException(BeeRuntimeException.BOOLEAN_EXPECTED_ERROR, exp.getToken(), ex);
		}

	}

	public int condtionCompare(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{
		Object v1 = eval(a, ctx);
		Object v2 = eval(b, ctx);
		Comparable c1;
		Comparable c2;
		if (v1 instanceof Comparable)
		{
			c1 = (Comparable) v1;
		}
		else
		{
			throw new BeeRuntimeException(BeeRuntimeException.BOOLEAN_EXPECTED_ERROR, a.getToken());
		}

		if (v2 instanceof Comparable)
		{
			c2 = (Comparable) v2;
		}
		else
		{
			throw new BeeRuntimeException(BeeRuntimeException.BOOLEAN_EXPECTED_ERROR, b.getToken());
		}

		return c1.compareTo(c2);

	}

	public boolean condtionEqualCompare(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{
		Object v1 = eval(a, ctx);
		Object v2 = eval(b, ctx);
		if (v1 != null || v2 != null)
		{
			if (v1 != null)
			{
				return v1.equals(v2);
			}
			else
			{
				return v2.equals(v1);
			}

		}
		else if (v1 == null)
		{
			return v2 == null;
		}
		else
		{
			return v1 == null;
		}
	}

	public Object eval(BeeCommonNodeTree exp, Context ctx)
	{

		try
		{
			int tokeType = exp.getToken().getType();
			switch (tokeType)
			{

				case BeeParser.TEXT_VAR_REFER:
				{
					// Log.key2Start();
					BeeCommonNodeTree textNode = (BeeCommonNodeTree) exp.getChild(0);
					String varName = textNode.getToken().getText();
					Object text = ctx.getTextVar(varName);
					((BeeCommonNodeTree) exp.getParent().getParent()).setCached(text);
					return text;

				}
				case BeeParser.VAR_REFER:
				{
					// Log.start("_var");
					try
					{
						Object o = evalVarRef(exp.getChildren(), ctx, exp);
						if (o instanceof Number)
						{
							return new BeeNumber(o.toString());
						}
						else
						{
							return o;
						}
					}
					finally
					{
						// Log.end("_var");
					}

				}

				case BeeParser.JSONARRAY:
				{
					int count = exp.getChildCount();
					List list = new ArrayList(count);
					BeeCommonNodeTree child = null;
					Object value = null;
					for (int i = 0; i < count; i++)
					{
						child = (BeeCommonNodeTree) exp.getChild(i);
						value = this.eval(child, ctx);
						list.add(value);
					}
					return list;
				}
				case BeeParser.JSONMAP:
				{
					int count = exp.getChildCount();
					Map map = new HashMap(count);
					BeeCommonNodeTree child = null;
					BeeCommonNodeTree keyTree = null;
					BeeCommonNodeTree valueTree = null;
					Object value = null;
					for (int i = 0; i < count; i++)
					{
						child = (BeeCommonNodeTree) exp.getChild(i);
						keyTree = (BeeCommonNodeTree) child.getChild(0);
						valueTree = (BeeCommonNodeTree) child.getChild(1);
						String varName = keyTree.getText();
						// antlr似乎没有执行StringLiteral
						varName = varName.substring(1, varName.length() - 1);
						map.put(varName, this.eval(valueTree, ctx));
					}
					return map;
				}
				case BeeParser.ADD:
				{
					return nodeAdd((BeeCommonNodeTree) exp.getChild(0), (BeeCommonNodeTree) exp.getChild(1), ctx);

				}
				case BeeParser.MINUS:
				{
					return nodeMinus((BeeCommonNodeTree) exp.getChild(0), (BeeCommonNodeTree) exp.getChild(1), ctx);
				}
				case BeeParser.MULTIP:
				{
					return nodeMutiple((BeeCommonNodeTree) exp.getChild(0), (BeeCommonNodeTree) exp.getChild(1), ctx);
				}
				case BeeParser.DIV:
				{
					return nodeDiv((BeeCommonNodeTree) exp.getChild(0), (BeeCommonNodeTree) exp.getChild(1), ctx);
				}
				case BeeParser.MOD:
				{
					return nodeMod((BeeCommonNodeTree) exp.getChild(0), (BeeCommonNodeTree) exp.getChild(1), ctx);
				}
				case BeeParser.NEGATOM:
				{
					BeeNumber number = (BeeNumber) this.eval((BeeCommonNodeTree) exp.getChild(0), ctx);
					return number.negate();

				}
				case BeeParser.INT:
				{
					return new BeeNumber(Integer.parseInt(exp.getToken().getText()));
				}
				case BeeParser.DOUBLE:
				{
					return new BeeNumber(Double.parseDouble(exp.getToken().getText()));

				}
				case BeeParser.BOOLEAN:
				{
					return new Boolean(exp.getToken().getText());
				}
				case BeeParser.StringLiteral:
				{
					String text = exp.getToken().getText();
					return text;
				}
				case BeeParser.FUNCTION:
				{
					return function(exp, ctx);
				}
				case BeeParser.CLASS_FUNCTION:
				{
					Object o = classNativeCall(exp, ctx);
					if (o instanceof Number)
					{
						if (o instanceof BigDecimal)
						{
							return new BeeNumber((BigDecimal) o);
						}
						else
						{
							return new BeeNumber(o.toString(), (Number) o);
						}
					}
					else
					{
						return o;

					}

				}
				case BeeParser.NULL:
				{
					return null;
				}
				default:
				{
					return condition(exp, ctx);
					// throw new BeeRuntimeException(
					// BeeRuntimeException.DO_NOT_SUPPORT, exp.getToken());
				}
			}

		}
		catch (BeeRuntimeException bre)
		{
			throw bre;
		}
		catch (Exception ex)
		{
			throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID, exp.getToken(), ex);
		}

	}

	public Object classNativeCall(BeeCommonNodeTree node, Context ctx)
	{
		BeeCommonNodeTree exp = (BeeCommonNodeTree) node;

		if (((BeeCommonNodeTree) exp.getChild(exp.getChildCount() - 1)).getToken().getType() == BeeParser.CLASS_METHOD)
		{
			// method call,first find the class or instance
			if (exp.getChildCount() == 2 && !isClassName((BeeCommonNodeTree) exp.getChild(0)))
			{
				// instance method .such as :aa.GetName();
				String identity = ((BeeCommonNodeTree) exp.getChild(0)).getToken().getText();
				Object o = ctx.getVar(identity);
				BeeCommonNodeTree classMethodNode = null;
				String methodName = null;
				Method method = null;

				classMethodNode = (BeeCommonNodeTree) exp.getChild(exp.getChildCount() - 1);
				methodName = ((BeeCommonNodeTree) classMethodNode.getChild(0)).getToken().getText();
				Object[] args = new Object[classMethodNode.getChildCount() - 1];
				Class[] parameterType = new Class[classMethodNode.getChildCount() - 1];
				for (int j = 1; j < classMethodNode.getChildCount(); j++)
				{
					args[j - 1] = this.eval((BeeCommonNodeTree) classMethodNode.getChild(j), ctx);
					parameterType[j - 1] = args[j - 1].getClass();
				}
				method = BeetlUtil.findMethod(o.getClass(), methodName, parameterType, exp, true);
				o = this.callMethod(o, method, args, exp);

				return o;

			}
			else
			{
				StringBuilder sb = new StringBuilder();
				Class target = null;
				Object o;
				for (int i = 0; i < exp.getChildCount() - 1; i++)
				{
					sb.append(exp.getChild(i).getText()).append(".");
				}
				sb.setLength(sb.length() - 1);

				try
				{
					target = Class.forName(sb.toString());

				}
				catch (SecurityException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							"SecurityException:" + e.getMessage());
				}
				catch (ClassNotFoundException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							"ClassNotFoundException:" + e.getMessage());
				}

				String methodName = null;
				Method method = null;

				BeeCommonNodeTree classMethodNode = (BeeCommonNodeTree) exp.getChild(exp.getChildCount() - 1);
				methodName = ((BeeCommonNodeTree) classMethodNode.getChild(0)).getToken().getText();
				Object[] args = new Object[classMethodNode.getChildCount() - 1];
				Class[] parameterType = new Class[classMethodNode.getChildCount() - 1];
				for (int j = 1; j < classMethodNode.getChildCount(); j++)
				{
					args[j - 1] = this.eval((BeeCommonNodeTree) classMethodNode.getChild(j), ctx);
					parameterType[j - 1] = args[j - 1].getClass();
				}

				method = BeetlUtil.findMethod(target, methodName, parameterType, exp, true);
				o = this.callMethod(null, method, args, exp);
				return o;

			}

		}
		else
		{
			if (exp.getChildCount() == 2 && !isClassName((BeeCommonNodeTree) exp.getChild(0)))
			{
				// public field of instance
				String identity = ((BeeCommonNodeTree) exp.getChild(0)).getToken().getText();
				Object o = ctx.getVar(identity);
				BeeCommonNodeTree classMethodNode = null;
				String propertyName = ((BeeCommonNodeTree) exp.getChild(exp.getChildCount() - 1)).getToken().getText();
				try
				{
					return o.getClass().getDeclaredField(propertyName).get(o);
				}
				catch (IllegalArgumentException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (SecurityException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (IllegalAccessException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (NoSuchFieldException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
			}
			else
			{
				StringBuilder sb = new StringBuilder();
				Class target = null;
				Object o;
				for (int i = 0; i < exp.getChildCount() - 1; i++)
				{
					sb.append(exp.getChild(i).getText()).append(".");
				}
				sb.setLength(sb.length() - 1);

				try
				{
					target = Class.forName(sb.toString());

				}
				catch (SecurityException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (ClassNotFoundException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}

				String propertyName = null;

				BeeCommonNodeTree propertyNode = (BeeCommonNodeTree) exp.getChild(exp.getChildCount() - 1);
				propertyName = propertyNode.getToken().getText();
				try
				{
					o = target.getDeclaredField(propertyName).get(null);
				}
				catch (IllegalArgumentException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (SecurityException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (IllegalAccessException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				catch (NoSuchFieldException e)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(),
							e.getMessage());
				}
				return o;

			}

		}

	}

	private boolean isClassName(BeeCommonNodeTree node)
	{
		String name = node.getToken().getText();
		char c = name.charAt(0);
		if (Character.isUpperCase(c))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	private Object callMethod(Object o, Method method, Object[] args, BeeCommonNodeTree exp)
	{
		try
		{
			// 检查是否有BeeNumber
			for (int i = 0; i < args.length; i++)
			{
				if (args[i] instanceof BeeNumber)
				{
					args[i] = ((BeeNumber) args[i]).orginalObject();
				}
			}
			method.setAccessible(true);
			//			System.out.println(method);
			o = method.invoke(o, args);
			return o;
		}
		catch (IllegalArgumentException e)
		{
			//debug
			//			System.out.println("class=" + o.getClass());
			//			System.out.println("method=" + method);
			//			for (int i = 0; i < args.length; i++)
			//			{
			//				System.out.println(args[0].getClass());
			//
			//			}
			throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(), e.getMessage());
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
			throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_INVALID, exp.getToken(), e.getMessage());
		}
		catch (InvocationTargetException e)
		{

			throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_EXCEPTION, exp.getToken(), e);
		}
	}

	public Object function(BeeCommonNodeTree exp, Context ctx)
	{

		BeeCommonNodeTree fnNameNode = ((BeeCommonNodeTree) exp.getChild(0));
		String fnName = (String) fnNameNode.getCached();
		if (fnName == null)
		{
			fnName = BeetlUtil.getFunctionFullName(fnNameNode);
			fnNameNode.setCached(fnName);
		}
		Template template = ((BeeTemplate) ctx.getVar("__this"));
		Writer writer = (Writer) ctx.getVar("__pw");
		Function fn = template.getFunction(fnName);
		if (fn == null)
		{
			throw new BeeRuntimeException(BeeRuntimeException.FUNCTION_NOT_FOUND,
					((BeeCommonNodeTree) exp.getChild(0)).getToken());
		}

		int size = exp.getChildCount();
		Object[] paras = new Object[size - 1];
		for (int i = 1; i < size; i++)
		{
			paras[i - 1] = eval((BeeCommonNodeTree) exp.getChild(i), ctx);
		}
		try
		{
			Context rootContext = ctx.getNewContext();
			rootContext.set("__line", fnNameNode.getToken().getLine());
			Object o = fn.call(paras, rootContext);
			if (o instanceof Number)
			{
				if (o instanceof BigDecimal)
				{
					return new BeeNumber((BigDecimal) o);
				}
				else
				{
					return new BeeNumber(o.toString(), (Number) o);
				}

			}
			else
			{
				return o;
			}
		}
		catch (Exception ex)
		{
			throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_EXCEPTION,
					((BeeCommonNodeTree) exp.getChild(0)).getToken(), ex);
		}

	}

	public Object evalVarRef(List<BeeCommonNodeTree> list, Context ctx, BeeCommonNodeTree exp)
	{

		int p = GroupTemplate.EXCEPTION;
		String defaultValue = null;
		int count = list.size();
		// 很多地方都需要异常处理，目前忽略
		lastNode = (BeeCommonNodeTree) list.get(0);

		String varName = lastNode.getToken().getText();
		Object value = null;
		try
		{
			value = ctx.getVar(varName);
		}
		catch (NullPointerException ex)
		{
			throw new BeeRuntimeException(BeeRuntimeException.VAR_NOT_DEFINED, lastNode.getToken(), ex.getMessage());
		}
		if (list.size() > 1)
		{
			if (list.get(list.size() - 1).getToken().getType() == BeeParser.StringLiteral)
			{
				if (exp.getParent().getType() == BeeParser.VAR_TEXT)
				{
					p = GroupTemplate.SHOW_NULL;
					defaultValue = list.get(list.size() - 1).getToken().getText();
					count = count - 1;
				}
				else
				{
					throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID, exp.getToken(),
							"只能在占位符里使用,如$user.wife.name?'bachelor'$");

				}
			}

		}
		else
		{
			return value;
		}
		Token token = null;

		for (int i = 1; i < count; i++)
		{
			if (value == null)
			{

				if (p == GroupTemplate.EXCEPTION)
				{
					throw new BeeRuntimeException(BeeRuntimeException.NULL, lastNode.getToken());
				}
				else
				{
					// 不需要执行后面的Fomart
					this.continueFormat = false;
					return defaultValue.substring(1, defaultValue.length() - 1);
				}
			}

			lastNode = (BeeCommonNodeTree) list.get(i);
			token = lastNode.getToken();
			int type = token.getType();
			if (type == BeeParser.MAP_LIST_INDEX)
			{

				lastNode = (BeeCommonNodeTree) lastNode.getChild(0);
				Object index = eval(lastNode, ctx);
				try
				{

					value = ctx.getValueAsMapListKey(value, index);
				}
				catch (IndexOutOfBoundsException ex)
				{
					throw new BeeRuntimeException(BeeRuntimeException.ARRAY_INDEX_ERROR, lastNode.getToken(),
							ex.getMessage());

				}
				catch (IllegalArgumentException ex)
				{
					BeeCommonNodeTree errorMapOrList = (BeeCommonNodeTree) list.get(i - 1);
					// 得到前一个符号
					BeeCommonNodeTree errorNode = (BeeCommonNodeTree) errorMapOrList.getChild(0);
					if (errorNode != null)
					{
						throw new BeeRuntimeException(BeeRuntimeException.CAST_LIST_OR_MAP_ERROR, errorNode.getToken(),
								this.mapOrListErrorDetail(list, i));

					}
					else
					{
						throw new BeeRuntimeException(BeeRuntimeException.CAST_LIST_OR_MAP_ERROR,
								errorMapOrList.getToken(), this.mapOrListErrorDetail(list, i));

					}

				}
				catch (Exception ex)
				{
					throw new BeeRuntimeException(BeeRuntimeException.ATTRIBUTE_INVALID, lastNode.getToken(),
							ex.getMessage());
				}

			}
			else if (type == BeeParser.VIRTUAL_ATTR_NAME)
			{
				lastNode = (BeeCommonNodeTree) lastNode.getChild(0);
				String attrName = lastNode.getToken().getText();

				VirtualAttributeEval veval = ((BeeTemplate) ctx.getVar("__this")).getVirtualAttributeEval(
						value.getClass(), attrName);
				if (veval != null)
				{
					try
					{
						value = veval.eval(value, attrName, ctx.getNewContext());

					}
					catch (Exception ex)
					{
						throw new BeeRuntimeException(BeeRuntimeException.NATIVE_CALL_EXCEPTION, lastNode.getToken(),
								ex.getMessage());
					}

				}
				else
				{
					throw new BeeRuntimeException(BeeRuntimeException.VIRTUAL_ATTRIBUTE_NOT_FOUND_EVAL,
							lastNode.getToken());
				}

			}

			else
			{
				// ATTR_Name
				lastNode = (BeeCommonNodeTree) lastNode.getChild(0);
				String attrName = lastNode.getToken().getText();

				try
				{
					value = ctx.getValueAttribute(value, attrName, lastNode);
				}
				catch (Exception ex)
				{
					throw new BeeRuntimeException(BeeRuntimeException.ATTRIBUTE_INVALID, lastNode.getToken(),
							ex.getMessage());
				}

			}

		}
		return value;
	}

	private String mapOrListErrorDetail(List<BeeCommonNodeTree> list, int i)
	{
		BeeCommonNodeTree errorMapOrList = (BeeCommonNodeTree) list.get(i - 1);
		// 得到前一个符号
		BeeCommonNodeTree errorNode = (BeeCommonNodeTree) errorMapOrList.getChild(0);
		if (errorNode == null)
		{
			errorNode = errorMapOrList;
		}
		return "必须是List或者Map [" + errorNode.getText() + "]";
	}

	public Object nodeMod(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{

		try
		{
			BeeNumber aValue = (BeeNumber) this.eval(a, ctx);
			BeeNumber bValue = (BeeNumber) this.eval(b, ctx);
			Long aLong = aValue.longValue();
			Long bLong = bValue.longValue();
			return new BeeNumber(aLong % bLong);

		}
		catch (ClassCastException cc)
		{
			//应该在语法阶段检查，为了保持语法文件简单，先暂时忽略
			throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID,
					((BeeCommonNodeTree) a.getParent()).getToken());

		}

	}

	public Object nodeDiv(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{
		try
		{
			BeeNumber aValue = (BeeNumber) this.eval(a, ctx);
			BeeNumber bValue = (BeeNumber) this.eval(b, ctx);
			BeeNumber number = ((BeeNumber) aValue).divide(((BeeNumber) bValue));
			return number;
		}
		catch (ClassCastException cc)
		{
			//应该在语法阶段检查，为了保持语法文件简单，先暂时忽略
			throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID,
					((BeeCommonNodeTree) a.getParent()).getToken());

		}
	}

	public Object div(Object aValue, Object bValue)
	{
		BeeNumber number = new BeeNumber(aValue.toString()).divide(bValue.toString());
		return number;
	}

	public Object nodeMutiple(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{
		try
		{
			BeeNumber aValue = (BeeNumber) this.eval(a, ctx);
			BeeNumber bValue = (BeeNumber) this.eval(b, ctx);
			BeeNumber number = ((BeeNumber) aValue).multiply(((BeeNumber) bValue));
			return number;
		}
		catch (ClassCastException cc)
		{
			//应该在语法阶段检查，为了保持语法文件简单，先暂时忽略
			throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID,
					((BeeCommonNodeTree) a.getParent()).getToken());

		}
	}

	public Object nodeMinus(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{
		try
		{
			BeeNumber aValue = (BeeNumber) this.eval(a, ctx);
			BeeNumber bValue = (BeeNumber) this.eval(b, ctx);
			BeeNumber number = ((BeeNumber) aValue).min(((BeeNumber) bValue));
			return number;
		}
		catch (ClassCastException cc)
		{
			//应该在语法阶段检查，为了保持语法文件简单，先暂时忽略
			throw new BeeRuntimeException(BeeRuntimeException.EXPRESSION_INVALID,
					((BeeCommonNodeTree) a.getParent()).getToken());

		}

	}

	public Object nodeAdd(BeeCommonNodeTree a, BeeCommonNodeTree b, Context ctx)
	{

		Object aValue = this.eval(a, ctx);
		Object bValue = this.eval(b, ctx);
		if (aValue instanceof String || bValue instanceof String)
		{

			return aValue.toString() + bValue.toString();
		}
		else if (aValue instanceof Character || bValue instanceof Character)
		{
			return aValue.toString() + bValue.toString();
		}
		else
		{
			BeeNumber number = ((BeeNumber) aValue).add(((BeeNumber) bValue));
			return number;
		}

	}

}
